package org.txazo.blog.commons.parse.base;

import java.io.BufferedWriter;
import java.io.IOException;

import org.txazo.blog.commons.io.base.Reader;

public class JavaParser extends AbstractParser {

	public static int flag = 0; // 字符串标记
	public static int doc = 0; // 文档注释标记
	public static int anno = 0; // Annotation标记
	public static int com = 0; // Java注释标记
	public static int sing = 0; // 单引号标记
	public static int doub = 0; // 双引号标记
	public static int pln = 0; // 空格标记
	public static final String[] kwds = { "package", "import", "class",
			"interface", "this", "super", "public", "private", "protected",
			"extends", "implements", "throw", "throws", "short", "int", "long",
			"byte", "char", "float", "double", "boolean", "if", "else", "true",
			"false", "static", "final", "transient", "volatile", "native",
			"void", "try", "catch", "finally", "switch", "case", "default",
			"break", "continue", "new", "abstract", "null", "return", "for",
			"do", "while", "synchronized", "instanceof", "enum", "assert" };
	public static final String[] plns = { "{", "}", "<", ">", "<=", ">=", "==",
			"!=", "+", "-", "*", "/", "%", "+=", "-=", "*=", "/=", "%=", "=",
			"&&", "||", "<<", ">>", "<<=", ">>=", "<<<", ">>>", "<<<=", ">>>=",
			"&", "|", "^", "&=", "|=", "^=", ":", "?" };
	public static final char[] single = { '{', '}', '[', ']', '(', ')', '<',
			'>', '+', '-', '!', '~' };
	public static final String[] spes = { "this", "super", "new", "null",
			"true", "false", "byte", "char", "short", "int", "long", "float",
			"double", "boolean", "final" };
	public static final char[] nexts = { ';', ')', '.', '[', ',' };

	public JavaParser(Reader reader) {
		super(reader);
	}

	@Override
	public void parse() throws IOException {
		String temp = null;
		writer.write("<span class=\"java-pln\">");
		while ((temp = reader.readLine()) != null) {
			parseJava(temp, writer);
		}
		writer.write("</span>");
	}

	public void parseJava(String line, BufferedWriter writer)
			throws IOException {
		if (line.equals("")) {
			// 空行
			writer.newLine();
		} else {
			// 非空行
			// 补全空格
			int i = 0;
			int length = line.length();
			for (; i < length; i++) {
				if (!(line.charAt(i) == 9)) {
					break;
				}
			}
			i *= 4;
			for (int j = 0; j < i; j++) {
				writer.write(" ");
			}
			// 去掉前后空格
			String trim = line.trim();
			if (trim.charAt(0) == '@' || anno != 0) {
				// Annotation注解
				anno(trim);
			} else if (trim.equals("/**")) {
				// 多行文档注释
				writer.write("<span class=\"java-doc\">/**");
				doc = 1;
			} else if (doc == 1) {
				// 多行文档注释
				if (trim.equals("*")) {
					writer.write(" *");
				} else if (trim.startsWith("* ")) {
					boldDoc(trim);
				} else if (trim.equals("*/")) {
					writer.write(" */</span>");
					doc = 0;
				}
			} else if (trim.startsWith("/** ") && trim.endsWith(" */")) {
				// 单行文档注释
				writer.write("<span class=\"java-doc\">" + trim + "</span>");
			} else if (trim.startsWith("/* ") || trim.startsWith("// ")) {
				// 单行Java注释
				writer.write("<span class=\"java-com\">" + trim + "</span>");
			} else {
				String[] array = trim.split(" ");
				for (String str : array) {
					int len = str.length();
					if (doub % 2 != 0 || sing % 2 != 0) {
						parse(str);
					} else if (com == 1) {
						// 行尾Java注释
						writer.write("<span class=\"java-com\">" + str
								+ " </span>");
					} else {
						if (str.equals("//") || str.equals("/*")) {
							// 行尾Java注释
							com = 1;
							writer.write("<span class=\"java-com\">" + str
									+ " </span>");
						} else if (isKwd(str)) {
							// 单独关键字
						} else if (isPln(str)) {
							// 运算符号
						} else if (isBeginWithKwd(str)) {
							// 关键字开头
						} else if (str.startsWith("System.out.")) {
							// 标准输出
							writer.write("System.<span class=\"java-kwd\">out</span>");
							parse(str.substring(10, len));
						} else {
							// 其它情况
							parse(str);
						}
					}
				}
				com = 0;
			}
			writer.newLine();
		}
	}

	/* 文档注释标记加粗 */
	public void boldDoc(String str) throws IOException {
		if (str.charAt(2) == '@') {
			int end = 0;
			for (int i = 3; i < str.length(); i++) {
				if (str.charAt(i) == ' ') {
					end = i;
					break;
				}
			}
			writer.write(" * <span class=\"java-bol\">" + str.substring(2, end)
					+ "</span>" + str.substring(end, str.length()));
		} else {
			writer.write(" " + str);
		}
	}

	/* Annotation注解 */
	public void anno(String str) throws IOException {
		int start = 0; // @位置
		boolean isAnno = false; // @Annotation是否处理完
		int length = str.length();
		for (int i = 0; i < length; i++) {
			char c = str.charAt(i);
			if (c == '@') {
				start = i;
				isAnno = true;
				continue;
			}
			if (isAnno == true) {
				// 无属性的Annotation
				if (i == length - 1) {
					writer.write("<span class=\"java-lit\">" + str + "</span>");
					break;
				}
				// @Annotation标记
				if (c == '(') {
					anno++;
					isAnno = false;
					writer.write("<span class=\"java-lit\">"
							+ str.substring(start, i)
							+ "</span><span class=\"java-pun\">(</span>");
				} else {
					continue;
				}
			} else {
				if (c == ')') {
					anno--;
					writer.write("<span class=\"java-pun\">)</span>");
				} else if (c == '"') {
					if (flag % 2 == 0) {
						writer.write("<span class=\"java-str\">\"");
					} else {
						writer.write("\"</span>");
					}
					flag++;
				} else if (c == '=' || c == '{' || c == '}') {
					writer.write("<span class=\"java-pun\">" + c + "</span>");
				} else {
					writer.write(c);
				}
			}
		}
	}

	/* 是否单独关键字 */
	public boolean isKwd(String str) throws IOException {
		for (String kwd : kwds) {
			if (str.equals(kwd)) {
				writer.write("<span class=\"java-kwd\">" + str + " </span>");
				return true;
			}
		}
		return false;
	}

	/* 是否关键字开头 */
	public boolean isBeginWithKwd(String str) throws IOException {
		int len = str.length();
		for (String spe : spes) {
			if (str.startsWith(spe)) {
				int length = spe.length();
				if (length == len) {
					writer.write("<span class=\"java-kwd\">" + spe + " </span>");
					return true;
				} else if (isNext(str.charAt(length))) {
					writer.write("<span class=\"java-kwd\">" + spe + "</span>");
					parse(str.substring(length, len));
					return true;
				}
				break;
			}
		}
		return false;
	}

	/* 是否匹配下一个字符 */
	public boolean isNext(char c) {
		for (char next : nexts) {
			if (c == next) {
				return true;
			}
		}
		return false;
	}

	/* 是否运算符号 */
	public boolean isPln(String str) throws IOException {
		StringBuilder sb = null;
		for (String pln : plns) {
			if (pln.equals(str)) {
				if (str.startsWith("<")) {
					int count = str.lastIndexOf("<");
					sb = new StringBuilder();
					for (int i = 0; i <= count; i++) {
						sb.append("&lt;");
					}
					writer.write("<span class=\"java-pun\">" + sb.toString()
							+ str.substring(count + 1, str.length())
							+ " </span>");
				} else if (str.startsWith(">")) {
					int count = str.lastIndexOf(">");
					sb = new StringBuilder();
					for (int i = 0; i <= count; i++) {
						sb.append("&gt;");
					}
					writer.write("<span class=\"java-pun\">" + sb.toString()
							+ str.substring(count + 1, str.length())
							+ " </span>");
				} else {
					writer.write("<span class=\"java-pun\">" + str + " </span>");
				}
				return true;
			}
		}
		return false;
	}

	/* 其它情况 */
	public void parse(String str) throws IOException {
		for (int i = 0; i < str.length(); i++) {
			char c = str.charAt(i);
			if (c == '"' && sing % 2 == 0) {
				// 双引号
				if (doub % 2 == 0) {
					writer.write("<span class=\"java-str\">\"");
					doub++;
				} else {
					if (i > 1 && str.charAt(i - 1) == '\\') {
						writer.write("\"");
					} else {
						writer.write("\"</span>");
						doub++;
					}
				}
			} else if (doub % 2 == 1) {
				// 双引号字符串
				writer.write(c);
			} else if (c == '\'') {
				// 单引号
				if (sing % 2 == 0) {
					writer.write("<span class=\"java-str\">'");
					sing++;
				} else {
					if (i > 1 && str.charAt(i - 1) == '\'') {
						writer.write("'");
					} else {
						writer.write("'</span>");
						sing++;
					}
				}
			} else if (sing % 2 == 1) {
				// 单引号字符串
				writer.write(c);
			} else if (isSingle(c)) {
				// 单个特殊符号
				if (c == '(' || c == '!') {
					// 括号后关键字
					if (isBeginWithKwd(str.substring(i + 1, str.length()))) {
						pln = 1;
						break;
					}
				}
			} else {
				writer.write(c);
			}
		}
		if (pln == 1) {
			pln = 0;
		} else {
			writer.write(" ");
		}
	}

	/* 是否单个特殊符号 */
	public boolean isSingle(char c) throws IOException {
		for (char s : single) {
			if (c == s) {
				if (c == '<') {
					writer.write("<span class=\"java-pun\">&lt;</span>");
				} else if (c == '>') {
					writer.write("<span class=\"java-pun\">&gt;</span>");
				} else {
					writer.write("<span class=\"java-pun\">" + c + "</span>");
				}
				return true;
			}
		}
		return false;
	}

}
